/*
 * Copyright 2011 Clean GWT
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.cleangwt.user.client.ui;

import com.cleangwt.user.client.ui.TablePanel.ColSpan;
import com.cleangwt.user.client.ui.TablePanel.HorizontalAlignCell;
import com.cleangwt.user.client.ui.TablePanel.RowSpan;
import com.cleangwt.user.client.ui.TablePanel.TableLayoutCell;
import com.cleangwt.user.client.ui.TablePanel.VerticalAlignCell;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.HeadingElement;
import com.google.gwt.dom.client.ParagraphElement;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.TextAlign;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Widget;

/**
 * This class providing convenient methods for laying widgets in-line.
 * 
 * @author Jess
 * @version 1.0
 * @since 1.0
 * @see TablePanel
 */
public class Lay {

  /**
   * Creates a widget that using &lt;div&gt; element with the given html.
   * 
   * @param html the html
   * @return the &lt;div&gt; widget
   */
  public static Widget block(String html) {
    return new RawWidget(DivElement.TAG, html);
  }

  /**
   * Wraps the given layout data into a {@link TableLayoutCell} with the BOTTOM alignment.
   * 
   * @param layoutData the layout data
   * @return the {@link VerticalAlignCell}
   */
  public static VerticalAlignCell bottom(Object layoutData) {
    return new VerticalAlignCell(HasVerticalAlignment.ALIGN_BOTTOM, layoutData);
  }

  /**
   * Creates a vertical layout with the given layout data and wraps it into
   * {@link VerticalAlignCell} BOTTOM.
   * 
   * @param layoutData the layout data
   * @return the {@link VerticalAlignCell}
   */
  public static VerticalAlignCell bottom(Object... layoutData) {
    return bottom(ver(layoutData));
  }

  /**
   * Wraps the given layout data into a {@link TableLayoutCell} with the CENTER alignment.
   * 
   * @param layoutData the layout data
   * @return the {@link HorizontalAlignCell}
   */
  public static HorizontalAlignCell center(Object layoutData) {
    return new HorizontalAlignCell(HasHorizontalAlignment.ALIGN_CENTER, layoutData);
  }

  /**
   * Creates a horizontal layout with the given layout data and wraps it into
   * {@link HorizontalAlignCell} CENTER.
   * 
   * @param layoutData the layout data
   * @return the {@link HorizontalAlignCell}
   */
  public static HorizontalAlignCell center(Object... layoutData) {
    return center(hor(layoutData));
  }

  /**
   * Adds a style to the given widget.
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget clazz(String clazz, Widget widget) {
    widget.addStyleName(clazz);
    return widget;
  }

  /**
   * Wraps the given layout data into a {@link TableLayoutCell} with the specified col span.
   * 
   * @param span the row span
   * @param layoutData the layout data
   * @return the {@link ColSpan}
   */
  public static ColSpan colSpan(int span, Object layoutData) {
    return new ColSpan(span, layoutData);
  }

  /**
   * Sets the given widget's width and height to '100%';
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget stretch(Widget w) {
    w.setWidth("100%");
    w.setHeight("100%");
    return w;
  }

  /**
   * Creates a {@link FlowPanel} with the given layout widgets.
   * 
   * @param widgets the widgets
   * @return the {@link FlowPanel}
   */
  public static FlowPanel flow(Widget... widgets) {
    assert widgets.length > 0;
    FlowPanel layout = new FlowPanel();
    for (Widget w : widgets) {
      layout.add(w);
    }
    return layout;
  }

  /**
   * Creates a widget that using &lt;h1~6&gt; element with the given html.
   * 
   * @param html the html
   * @return the &lt;div&gt; widget
   */
  public static Widget heading(int n, String html) {
    HeadingElement h = Document.get().createHElement(n);
    h.setInnerHTML(html);
    return new RawWidget(h);
  }

  /**
   * Creates a widget that using &lt;h4&gt; element with the given html.
   * 
   * @param html the html
   * @return the &lt;div&gt; widget
   */
  public static Widget heading(String html) {
    return heading(4, html);
  }

  /**
   * Sets the height property for the given widget.
   * 
   * @param w the widget
   * @param height the height to set
   * @return the widget itself
   */
  public static Widget height(int height, Widget w) {
    w.getElement().getStyle().setHeight(height, Unit.PX);
    return w;
  }

  /**
   * Creates a widget with the specified width to make a horizontal offset.
   * 
   * @param offset the horizontal offset
   * @return the widget to make a horizontal offset
   */
  public static Widget hOffset(int offset) {
    return width(offset, new RawWidget(SpanElement.TAG));
  }

  /**
   * Creates a {@link TablePanel} with the given layout data to build horizontal layout.
   * 
   * @param widgets the widgets
   * @return the {@link TablePanel}
   */
  public static TablePanel hor(Object... layoutData) {
    TablePanel layout = new TablePanel();
    layout.addRow(layoutData);
    return layout;
  }

  /**
   * Sets the given widget's width style to '100%';
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget hStretch(Widget w) {
    w.setWidth("100%");
    return w;
  }

  /**
   * Creates a {@link TablePanel} for doing layout with the given layout object.
   * 
   * @param layoutData the layout data
   * @return the {@link TablePanel}
   */
  public static TablePanel layout(Object layoutData) {
    TablePanel layout = new TablePanel();
    layout.addRow(layoutData);
    layout.setSize("100%", "100%");
    return layout;
  }

  /**
   * Wraps the given layout data into a {@link TableLayoutCell} with the LEFT alignment.
   * 
   * @param layoutData the layout data
   * @return the {@link HorizontalAlignCell}
   */
  public static HorizontalAlignCell left(Object layoutData) {
    return new HorizontalAlignCell(HasHorizontalAlignment.ALIGN_LEFT, layoutData);
  }

  /**
   * Creates a horizontal layout with the given layout data and wraps it into
   * {@link HorizontalAlignCell} LEFT.
   * 
   * @param layoutData the layout data
   * @return the {@link HorizontalAlignCell}
   */
  public static HorizontalAlignCell left(Object... layoutData) {
    return left(hor(layoutData));
  }

  /**
   * Wraps the given layout data into a {@link TableLayoutCell} with the MIDDLE alignment.
   * 
   * @param layoutData the layout data
   * @return the {@link VerticalAlignCell}
   */
  public static VerticalAlignCell middle(Object layoutData) {
    return new VerticalAlignCell(HasVerticalAlignment.ALIGN_MIDDLE, layoutData);
  }

  /**
   * Creates a vertical layout with the given layout data and wraps it into
   * {@link VerticalAlignCell} MIDDLE.
   * 
   * @param layoutData the layout data
   * @return the {@link VerticalAlignCell}
   */
  public static VerticalAlignCell middle(Object... layoutData) {
    return middle(ver(layoutData));
  }

  /**
   * Creates a widget that using &lt;p&gt; element with the given html.
   * 
   * @param html the html
   * @return the &lt;div&gt; widget
   */
  public static Widget p(String html) {
    return new RawWidget(ParagraphElement.TAG, html);
  }

  /**
   * Lays each widget with a fit space to a panel that use &lt;p&gt; element.
   * 
   * @param widgets the widgets to lay
   * @return a panel wraps all the widgets
   */
  public static Widget p(Widget... widgets) {
    assert widgets.length > 0;
    HTMLPanel layout = new HTMLPanel(ParagraphElement.TAG, "");
    for (Widget w : widgets) {
      layout.getElement().appendChild(Document.get().createTextNode(" "));
      layout.add(w);
    }
    return layout;
  }

  /**
   * Sets the given widget's float style to 'left'.
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget pullLeft(Widget w) {
    w.getElement().getStyle().setFloat(Style.Float.LEFT);
    return w;
    // return clazz(Styles.PULL_LEFT, w);
  }

  /**
   * Sets the given widget's float style to 'right'.
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget pullRight(Widget w) {
    w.getElement().getStyle().setFloat(Style.Float.RIGHT);
    return w;
    // return clazz(Styles.PULL_RIGHT, w);
  }

  /**
   * Creates a {@link RawWidget} with the given tag and html.
   * 
   * @param tag the element tag
   * @param html the html
   * @return a {@link RawWidget}
   */
  public static Widget raw(String tag, String html) {
    return new RawWidget(tag, html);
  }

  /**
   * Wraps the given layout data into a {@link TableLayoutCell} with the RIGHT alignment.
   * 
   * @param layoutData the layout data
   * @return the {@link HorizontalAlignCell}
   */
  public static HorizontalAlignCell right(Object layoutData) {
    return new HorizontalAlignCell(HasHorizontalAlignment.ALIGN_RIGHT, layoutData);
  }

  /**
   * Creates a horizontal layout with the given layout data and wraps it into
   * {@link HorizontalAlignCell} RIGHT.
   * 
   * @param layoutData the layout data
   * @return the {@link HorizontalAlignCell}
   */
  public static HorizontalAlignCell right(Object... layoutData) {
    return right(hor(layoutData));
  }

  /**
   * Wraps the given layout data into a {@link TableLayoutCell} with the specified row span.
   * 
   * @param span the row span
   * @param layoutData the layout data
   * @return the {@link RowSpan}
   */
  public static RowSpan rowSpan(int span, Object layoutData) {
    return new RowSpan(span, layoutData);
  }

  /**
   * Creates a widget that using &lt;span&gt; element with the given html.
   * 
   * @param html the html
   * @return the &lt;div&gt; widget
   */
  public static Widget span(String html) {
    return new RawWidget(SpanElement.TAG, html);
  }

  /**
   * Sets the given widget's height style to '100%';
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget vStretch(Widget w) {
    w.setHeight("100%");
    return w;
  }

  /**
   * Sets the style name for the given widget.
   * 
   * @param style the style to set
   * @param w the widget
   * @return the widget itself
   */
  public static Widget style(String style, Widget widget) {
    widget.setStyleName(style);
    return widget;
  }

  /**
   * Creates a widget that using &lt;span&gt; element with the given html.
   * 
   * @param html the html
   * @return
   */
  public static RawWidget text(String html) {
    return new RawWidget(SpanElement.TAG, html);
  }

  /**
   * Sets the given widget's text-align to 'center'.
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget textCenter(Widget w) {
    w.getElement().getStyle().setTextAlign(TextAlign.CENTER);
    return w;
  }

  /**
   * Sets the given widget's text-align to 'left'.
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget textLeft(Widget w) {
    w.getElement().getStyle().setTextAlign(TextAlign.LEFT);
    return w;
  }

  /**
   * Sets the given widget's text-align to 'right'.
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget textRight(Widget w) {
    w.getElement().getStyle().setTextAlign(TextAlign.RIGHT);
    return w;
  }

  /**
   * Sets the given widget's display style to 'inline'.
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget inline(Widget w) {
    w.getElement().getStyle().setDisplay(Display.INLINE);
    return w;
  }

  /**
   * Sets the given widget's display style to 'block'.
   * 
   * @param w the widget
   * @return the widget itself
   */
  public static Widget block(Widget w) {
    w.getElement().getStyle().setDisplay(Display.BLOCK);
    return w;
  }

  /**
   * Wraps the given layout data into a {@link TableLayoutCell} with the TOP alignment.
   * 
   * @param layoutData the layout data
   * @return the {@link VerticalAlignCell}
   */
  public static VerticalAlignCell top(Object layoutData) {
    return new VerticalAlignCell(HasVerticalAlignment.ALIGN_TOP, layoutData);
  }

  /**
   * Creates a vertical layout with the given layout data and wraps it into
   * {@link VerticalAlignCell} TOP.
   * 
   * @param layoutData the layout data
   * @return the {@link VerticalAlignCell}
   */
  public static VerticalAlignCell top(Object... layoutData) {
    return top(ver(layoutData));
  }

  /**
   * Creates a {@link TablePanel} with the given layout data to build vertical layout.
   * 
   * @param widgets the widgets
   * @return the {@link TablePanel}
   */
  public static TablePanel ver(Object... widgets) {
    assert widgets.length > 0;
    TablePanel layout = new TablePanel();
    for (Object w : widgets) {
      layout.addRow(w);
    }
    return layout;
  }

  /**
   * Creates a widget with the specified height to make a vertical offset.
   * 
   * @param offset the vertical offset
   * @return the widget to make a vertical offset
   */
  public static Widget vOffset(int offset) {
    return height(offset, new RawWidget(SpanElement.TAG));
  }

  /**
   * Sets the width property for the given widget.
   * 
   * @param w the widget
   * @param width the width to set
   * @return the widget itself
   */
  public static Widget width(int width, Widget w) {
    // ensure inline-block display
    // w.getElement().getStyle().setDisplay(Display.INLINE_BLOCK);
    w.getElement().getStyle().setWidth(width, Unit.PX);
    return w;
  }

}
